package cn.hzy.admin.core.filter;

import cn.hzy.admin.models.SysUser;
import cn.hzy.admin.services.system.ISysUserService;
import cn.hzy.toolkit.ApiResult;
import cn.hzy.toolkit.JwtTokenUtil;
import cn.hzy.toolkit.annotation.HzyAuthorization;
import com.alibaba.fastjson.JSONObject;
import org.apache.logging.log4j.util.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Objects;

/**
 * <p>
 * 请求 过滤器
 * </p>
 *
 * @author hzy
 * @since 2020-04-26
 */
public class FilterHandlerInterceptor implements HandlerInterceptor {

    private final Logger logger = LoggerFactory.getLogger(FilterHandlerInterceptor.class);
    private final static String logOutMessage = "未授权，请登陆授权！";
    private final static String logOutPath = "/logOut";
    //service
    private final ISysUserService sysUserService;

    public FilterHandlerInterceptor(ISysUserService sysUserService) {
        this.sysUserService = sysUserService;
    }

    /**
     * 处理 HandlerAdapte 业务 之前调用
     *
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    @ResponseBody
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //获取 授权 注解
        if (handler instanceof HandlerMethod) {
            var handlerMethod = (HandlerMethod) handler;
            var method = handlerMethod.getMethod();
            //先找 类 中 是否有 注解
            var classMethod = method.getDeclaringClass();
            var hzyAuthorization = classMethod.getAnnotation(HzyAuthorization.class);
            //如果 类 上面 没有 注解 则 函数体上面找
            if (Objects.isNull(hzyAuthorization)) hzyAuthorization = method.getAnnotation(HzyAuthorization.class);
            //如果添加了 HzyAuthorization 注解
            if (Objects.nonNull(hzyAuthorization)) {
                //检查标记是否忽略验证
                if (!hzyAuthorization.value()) {
                    return this.checkAuth(request, response, handler);
                }
            }
        }

        return true;
    }

    /**
     * 处理 HandlerAdapte 业务 之后调用
     *
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    /**
     * 请求处理 业务 完成后回调
     *
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }

    /**
     * 授权 检查
     *
     * @param request
     * @param response
     * @param handler
     * @return
     */
    private boolean checkAuth(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //this.logger.info("request请求地址path[{}] uri[{}]", request.getServletPath(), request.getRequestURI());
        System.out.println("request请求地址path[" + request.getServletPath() + "] uri[" + request.getRequestURI() + "]");
        //验证 token
        var tokenValue = this.sysUserService.getToken();
        if (Strings.isEmpty(tokenValue)) {
            this.result(request, response);
            return false;
        }

        //验证 token 是否有效
        var sysUser = JwtTokenUtil.unsign(tokenValue, SysUser.class);

        if (sysUser == null) {
            this.result(request, response);
            return false;
        }

        System.out.println("用户:" + sysUser.getAccountName() + "已通过授权!");

        return true;
    }

    /**
     * 返回数据
     *
     * @param request
     * @param response
     * @throws Exception
     */
    private void result(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 如果是 ajax
        var xRequestedWidth = request.getHeader("x-requested-width");
        var isAjaxRequest = Strings.isNotEmpty(xRequestedWidth) && xRequestedWidth.equals("XMLHttpRequest");
        if (isAjaxRequest) {
            this.jsonResult(response, logOutMessage, logOutPath);
            return;
        }
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("" +
                "<script type='text/javascript'>" +
                "   alert(' " + logOutMessage + " ');" +
                "   top.window.location='/logOut';" +
                "</script>" +
                "");
        this.contentResult(response, stringBuilder);
    }

    /**
     * 返回 Json 数据
     *
     * @param response
     * @param msg
     * @throws Exception
     */
    private void jsonResult(HttpServletResponse response, String msg, Object data) throws Exception {
        response.setContentType("application/json; charset=utf-8");
        var printWriter = response.getWriter();
        var apiResult = new ApiResult(ApiResult.StatusCodeEnum.UnAuth, msg, data);
        printWriter.print(JSONObject.toJSONString(apiResult));
        printWriter.flush();
        printWriter.close();
    }

    /**
     * 返回 文本 数据
     *
     * @param response
     * @param msg
     * @throws Exception
     */
    private void contentResult(HttpServletResponse response, StringBuilder msg) throws Exception {
        response.setContentType("text/html; charset=utf-8");
        var printWriter = response.getWriter();
        printWriter.print(msg);
        printWriter.flush();
        printWriter.close();
    }

}
